/**
 * @description 提供HTTP请求常用工具
 */

/**
 * 请求选项配置
 * @property {string} url - 请求URL
 * @property {string} [method=GET] - 请求方法，默认为GET
 * @property {Records} [headers={}] - 请求头信息，默认包含Content-Type: application/json
 * @property {Records} [data={}] - 请求体数据，适用于POST/PUT等方法，会自动序列化为JSON
 * @property {Records} [params={}] - URL查询参数，会自动序列化为查询字符串拼接到URL
 * @property {number} [timeout=5000] - 超时时间(ms)，默认5000ms
 * @property {boolean} [responseRaw=false] - 是否返回原始响应文本而非JSON解析结果，默认false
 * @property {string} [auth] - 认证令牌(Bearer)，设置后会自动添加Authorization头
 * @property {AbortSignal} [signal] - 外部AbortSignal，用于手动取消请求
 * @property {boolean} [returnResponse=false] - 是否返回原始Response对象而非解析后的数据，默认false
 */
export interface RequestOptions {
    url: string;
    /** 请求方法，默认为GET */
    method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD';
    /** 请求头信息，默认包含Content-Type: application/json */
    headers?: Record<string, string>;
    /** 请求体数据，适用于POST/PUT等方法，会自动序列化为JSON */
    data?: Record<string, string>;
    /** URL查询参数，会自动序列化为查询字符串拼接到URL */
    params?: Record<string, string>;
    /** 超时时间(ms)，默认5000ms */
    timeout?: number;
    /** 是否返回原始响应文本而非JSON解析结果，默认false */
    responseRaw?: boolean;
    /** 认证令牌(Bearer)，设置后会自动添加Authorization头 */
    auth?: string;
    /** 外部AbortSignal，用于手动取消请求 */
    signal?: AbortSignal;
    /** 是否返回原始Response对象而非解析后的数据，默认false */
    returnResponse?: boolean;
}

/**
 * 基础请求函数
 * @template T - 响应数据类型
 * @param {string} url - 请求URL
 * @param {RequestOptions} [options={}] - 请求配置选项
 * @returns {Promise<T>} - 解析后的响应数据
 * @throws {Error} - 请求失败或超时错误
 * @example
 * request<User>('/api/users/1', { auth: 'token' })
 *   .then(user => console.log('User data:', user))
 *   .catch(error => console.error('Request failed:', error.message));
 */
export const request = async <T = any>(options: RequestOptions): Promise<T> => {
    const {
        url,
        method = 'GET',
        headers = {},
        data,
        params,
        timeout = 5000,
        responseRaw = false,
        returnResponse = false,
        signal
    } = options;

    // 处理URL参数
    // 直接使用传入的URL
    const fullUrl = new URL(url);
    if (params) {
        Object.entries(params).forEach(([key, value]) => {
            if (value !== undefined && value !== null) {
                fullUrl.searchParams.append(key, value);
            }
        });
    }
    const requestUrl = fullUrl.toString();

    // 默认请求头
    // 处理认证头
    const authHeaders = options.auth ? { Authorization: `Bearer ${options.auth}` } : {};
    const defaultHeaders: Record<string, any> = {
        'Content-Type': 'application/json',
        ...authHeaders,
        ...headers
    };

    // 请求配置
    const fetchOptions: RequestInit = {
        method,
        headers: defaultHeaders,
        body: data ? JSON.stringify(data) : undefined,
        signal: signal || (() => {
            const controller = new AbortController();
            setTimeout(() => controller.abort(), timeout);
            return controller.signal;
        })()
    };

    try {
        const response = await fetch(requestUrl, fetchOptions);

        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }

        if (returnResponse) {
            return response as unknown as T;
        } else if (responseRaw) {
            return await response.text() as unknown as T;
        } else {
            return await response.json() as T;
        }
    } catch (error) {
        if (error instanceof Error && error.name === 'AbortError') {
            throw new Error(`Request timeout after ${timeout}ms`);
        }
        throw error;
    }
};

/**
 * GET请求
 * @template T - 响应数据类型
 * @param {string} url - 请求URL
 * @param {Omit<RequestOptions, 'method'>} [options={}] - 请求配置选项
 * @returns {Promise<T>} - 响应数据
 * @example
 * get<User>('/api/users/1')
 *   .then(user => console.log('User:', user));
 */
export const get = <T = any>(options: Omit<RequestOptions, 'method'>): Promise<T> => {
    return request<T>({ ...options, method: 'GET' });
};

/**
 * POST请求
 * @template T - 响应数据类型
 * @param {string} url - 请求URL
 * @param {Records} [data] - 请求体数据
 * @param {Omit<RequestOptions, 'method' | 'data'>} [options={}] - 请求配置选项
 * @returns {Promise<T>} - 响应数据
 * @example
 * post<User>('/api/users', { name: 'John', age: 30 })
 *   .then(user => console.log('Created user:', user));
 */
export const post = <T = any>(options: Omit<RequestOptions, 'method'>): Promise<T> => {
    return request<T>({ ...options, method: 'POST' });
};

/**
 * PUT请求
 * @template T - 响应数据类型
 * @param {string} url - 请求URL
 * @param {Records} [data] - 请求体数据
 * @param {Omit<RequestOptions, 'method' | 'data'>} [options={}] - 请求配置选项
 * @returns {Promise<T>} - 响应数据
 * @example
 * put<User>('/api/users/1', { name: 'John', age: 30 })
 *   .then(user => console.log('Updated user:', user));
 */
export const put = <T = any>(options: Omit<RequestOptions, 'method'>): Promise<T> => {
    return request<T>({ ...options, method: 'PUT' });
};

/**
 * DELETE请求
 * @template T - 响应数据类型
 * @param {string} url - 请求URL
 * @param {Omit<RequestOptions, 'method'>} [options={}] - 请求配置选项
 * @returns {Promise<T>} - 响应数据
 * @example
 * deleteRequest('/api/users/1')
 *   .then(() => console.log('User deleted successfully'));
 */
export const deleteRequest = <T = any>(options: Omit<RequestOptions, 'method'>): Promise<T> => {
    return request<T>({ ...options, method: 'DELETE' });
};

/**
 * 获取原始响应体
 * @template T - 响应数据类型(字符串)
 * @param {string} url - 请求URL
 * @param {Omit<RequestOptions, 'responseRaw'>} [options={}] - 请求配置选项
 * @returns {Promise<T>} - 原始响应文本
 * @example
 * body<string>('/api/data')
 *   .then(rawData => console.log('Raw response:', rawData));
 */
export const body = <T = any>(options: Omit<RequestOptions, 'responseRaw'>): Promise<T> => {
    return request<T>({ ...options, responseRaw: true });
};